﻿namespace _06_Snake
{
    struct Pos
    {
        public int x;
        public int y;
        // 运算符重载
        // public static 返回类型 operator 你要重载的运算符（参数列表）{运算规则}
        // 注意 有些运算符需要配对重载
        public static bool operator ==( Pos left, Pos right)
        {
            return left.x == right.x && left.y == right.y;
        }
        public static bool operator !=(Pos left, Pos right)
        {
            return left.x != right.x || left.y != right.y;
        }
    }
    internal class Snake
    {
        enum Direction
        {
            Null,
            Up,
            Down, 
            Left, 
            Right,
        }

        // 属性与方法
        int length;
        public Pos[] pos;
        Direction dir;
        int width;
        int height;
        ConsoleKeyInfo key;
        Food food;
        Game game;
        
        public Snake(int width, int height)
        {
            this.width = width;
            this.height = height;
            pos = new Pos[(width - 2) * (height-2)];
        }
        void Move()
        {
            // 蛇的移动 本质上就是 数组元素在后移 头更新

            // 数组元素后移
            for (int i = length; i > 0; i--)
            {
                pos[i] = pos[i-1];
            }

            // 头更新
            switch (dir)
            {
                case Direction.Up:
                    pos[0].y--;
                    break;
                case Direction.Down:
                    pos[0].y++;
                    break;
                case Direction.Left:
                    pos[0].x--;
                    break;
                case Direction.Right:
                    pos[0].x++;
                    break;
            }

            game.isOver = CheckOver();
        }

        public void Grow()
        {
            length++;
        }

        Direction GetDirection()
        {
            if (pos[0].x == pos[1].x)
            {
                if (pos[0].y - pos[1].y > 0)
                {
                    return Direction.Down;
                }
                else if (pos[0].y - pos[1].y < 0)
                {
                    return Direction.Up;
                }
            }
            else if (pos[0].y == pos[1].y)
            {
                if (pos[0].x - pos[1].x > 0)
                {
                    return Direction.Right;
                }
                else if (pos[0].x - pos[1].x < 0)
                {
                    return Direction.Left;
                }
            }
            return Direction.Null;
        }

        public bool OnBody(Pos pos)
        {
            for (int i = 0; i < length; i++)
            {
                if (pos == this.pos[i])
                {
                    return true;
                }
            }
            return false;
        }

        bool CheckOver()
        {
            // 如果头碰到身子 就死
            for (int i = 1; i < length; i++)
            {
                if (pos[0] == pos[i])
                {
                    return true;
                }
            }
            return false;
        }

        public void Init(Food food, Game game)
        {
            length = 3;
            dir = Direction.Right;
            pos[0].x = width / 2;
            pos[0].y = height / 2;
            this.food = food;
            this.game = game;
        }

        public void Input()
        {
            key = default;
            if (Console.KeyAvailable)
            {
                key = Console.ReadKey(true);
            }
            switch (key.Key)
            {
                case ConsoleKey.W:
                case ConsoleKey.UpArrow:
                    if(GetDirection() != Direction.Down)
                    {
                        dir = Direction.Up;
                        break;
                    }
                    break;
                case ConsoleKey.S:
                case ConsoleKey.DownArrow:
                    if(GetDirection() != Direction.Up)
                    {
                        dir = Direction.Down;
                        break;
                    }
                    break;
                case ConsoleKey.A:
                case ConsoleKey.LeftArrow:
                    if(GetDirection() != Direction.Right)
                    {
                        dir = Direction.Left;
                        break;
                    }
                    break;
                case ConsoleKey.D:
                case ConsoleKey.RightArrow:
                    if(GetDirection() != Direction.Left)
                    {
                        dir = Direction.Right;
                        break;
                    }
                    break;
                case ConsoleKey.Q:
                    Grow();
                    break;
            }
        }

        public void Update() 
        {
            if (pos[0] == food.pos)
            {
                Grow();
                food.Spawn();
            }
            if (pos[0].x < 1) pos[0].x = width - 2;
            if (pos[0].x > width-2) pos[0].x = 1;
            if (pos[0].y < 1) pos[0].y = height - 2;
            if (pos[0].y > height - 2) pos[0].y = 1;
        }

        public void FixUpdate()
        {
            Move();
        }

        public void Render()
        {
            for (int i = 0; i < length + 1; i++)
            {
                Console.SetCursorPosition(pos[i].x, pos[i].y);
                if (i == 0)
                {
                    Console.WriteLine("@");
                }
                else if(i == length)
                {
                    Console.WriteLine(" ");
                }
                else
                {
                    Console.WriteLine("o");
                }
            }
        }

        public void End()
        {

        }
    }
}
